import socket
import json
from datetime import datetime, timedelta
from db_utils import DatabaseUtils
from logger_module import log_error, log_info, log_debug

# 从配置获取操作日志设置
def get_operation_logging_config():
    """从配置文件获取操作日志设置"""
    try:
        from config_utils import ConfigManager
        config = ConfigManager.load_config()
        return config.get('operation_logging', {})
    except Exception as e:
            # 出错时使用默认配置
            # 静默处理配置获取失败
            return {
            'batch_size': 10,
            'max_batch_age': 60,
            'async_processing': False
        }

class OperationLogger:
    """操作日志记录器，用于记录用户操作日志"""
    
    def __init__(self):
        """初始化操作日志记录器"""
        # 从配置获取设置
        try:
            config = get_operation_logging_config()
            self.log_batch = []  # 批量日志缓存
            self.batch_size = config.get('batch_size', 10)  # 批量提交的阈值
            self.max_batch_age = config.get('max_batch_age', 60)  # 最大批处理等待时间（秒）
            self.async_processing = config.get('async_processing', False)  # 是否启用异步处理
            self.last_batch_time = datetime.now()  # 上次批处理时间
            
            # 异步处理相关（当前版本暂不实现完整异步功能，仅预留接口）
            self.processing_lock = False
        except Exception as e:
            # 记录初始化配置失败的错误，但允许程序继续运行
            # 使用日志系统记录错误，避免递归依赖
            try:
                log_error(f"初始化操作日志记录器失败: {str(e)}")
            except:
                pass  # 静默处理日志记录失败
            # 设置默认配置
            self.log_batch = []
            self.batch_size = 10
            self.max_batch_age = 60
            self.async_processing = False
            self.last_batch_time = datetime.now()
            self.processing_lock = False
    
    def get_connection(self):
        """获取数据库连接"""
        try:
            return DatabaseUtils.get_connection()
        except Exception as e:
            # 记录数据库连接错误
            log_error(f"获取数据库连接失败: {str(e)}")
            return None
    
    def get_ip_address(self):
        """获取本地IP地址"""
        try:
            # 获取本地主机名
            hostname = socket.gethostname()
            # 获取IP地址列表
            ip_addresses = socket.gethostbyname_ex(hostname)[2]
            # 返回非127.0.0.1的IP地址（如果存在）
            for ip in ip_addresses:
                if ip != '127.0.0.1':
                    return ip
            # 默认为127.0.0.1
            return '127.0.0.1'
        except Exception as e:
            log_error(f"获取IP地址失败: {str(e)}")
            return '未知IP'
    
    def log_operation(self, user_id=None, username=None, operation_module=None, 
                      operation_content=None, operation_result=None, detail=None):
        """
        记录操作日志
        
        Args:
            user_id: 用户ID
            username: 用户名
            operation_module: 操作模块
            operation_content: 操作内容
            operation_result: 操作结果（成功/失败）
            detail: 详细信息（JSON格式）
        """
        try:
            # 添加到批量缓存
            log_entry = {
                'log_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'user_id': user_id,
                'username': username or '未知用户',
                'operation_module': operation_module or '未知模块',
                'operation_content': operation_content or '未知操作',
                'operation_result': operation_result or '未知结果'
            }
            
            # 获取IP地址时增加异常处理
            try:
                log_entry['ip_address'] = self.get_ip_address()
            except Exception as e:
                log_entry['ip_address'] = '未知IP'
                log_error(f"获取IP地址失败: {str(e)}")
            
            # 处理详细信息时增加异常处理
            try:
                log_entry['detail'] = json.dumps(detail, ensure_ascii=False) if isinstance(detail, dict) else str(detail)
            except Exception as e:
                log_entry['detail'] = '详细信息格式错误'
                log_error(f"处理详细信息时出错: {str(e)}")
            
            # 添加到批量缓存
            self.log_batch.append(log_entry)
            
            # 检查是否需要提交日志：达到批量大小或超过最大等待时间
            current_time = datetime.now()
            if len(self.log_batch) >= self.batch_size or \
               (self.log_batch and (current_time - self.last_batch_time).total_seconds() >= self.max_batch_age):
                self.flush_logs()
        except Exception as e:
            # 记录日志操作本身的错误
            log_error(f"记录操作日志失败: {str(e)}")
    
    def flush_logs(self):
        """强制提交所有缓存的日志"""
        # 如果正在处理或没有日志，直接返回
        if self.processing_lock or not self.log_batch:
            return
        
        # 设置处理锁，避免并发提交
        self.processing_lock = True
        conn = None
        logs_to_process = []
        
        try:
            # 复制并清空日志批次，减少锁持有时间
            logs_to_process = self.log_batch.copy()
            self.log_batch = []
            self.last_batch_time = datetime.now()
            
            # 获取数据库连接
            conn = self.get_connection()
            if not conn:
                # 如果获取连接失败，将日志放回批次
                self.log_batch.extend(logs_to_process)
                log_debug("无法获取数据库连接，日志将稍后重试")
                return
            
            # 确保操作日志表存在
            try:
                DatabaseUtils.ensure_operation_logs_table_exists(conn)
            except Exception as table_error:
                log_error(f"确保日志表存在时出错: {str(table_error)}")
                # 将日志放回批次
                self.log_batch.extend(logs_to_process)
                return
            
            # 批量插入日志数据 - 优化版本
            query = '''INSERT INTO operation_logs 
                      (log_time, user_id, username, operation_module, operation_content, 
                       operation_result, ip_address, detail) 
                      VALUES (?, ?, ?, ?, ?, ?, ?, ?)'''
            
            # 分批处理大批次，避免单次事务过大
            batch_size = min(50, len(logs_to_process))  # 每批最多处理50条
            total_processed = 0
            
            for i in range(0, len(logs_to_process), batch_size):
                batch = logs_to_process[i:i + batch_size]
                
                # 准备数据列表，增加数据验证
                params_list = []
                try:
                    for entry in batch:
                        # 确保所有必要字段都存在且有效
                        log_time = str(entry.get('log_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
                        user_id = entry.get('user_id')
                        username = str(entry.get('username', '未知用户'))
                        operation_module = str(entry.get('operation_module', '未知模块'))
                        operation_content = str(entry.get('operation_content', '未知操作'))
                        operation_result = str(entry.get('operation_result', '未知结果'))
                        ip_address = str(entry.get('ip_address', '未知IP'))
                        detail = str(entry.get('detail', ''))
                        
                        params_list.append((log_time, user_id, username, 
                                           operation_module, operation_content, 
                                           operation_result, ip_address, detail))
                except Exception as data_error:
                    log_error(f"准备日志批次数据时出错: {str(data_error)}")
                    # 将失败的批次放回队列末尾
                    self.log_batch.extend(batch)
                    break
                
                # 批量执行插入
                try:
                    success = DatabaseUtils.execute_batch(conn, query, params_list)
                    if success:
                        total_processed += len(batch)
                    else:
                        log_error(f"批量插入操作日志失败，批次索引: {i}")
                        # 将失败的批次放回队列末尾
                        self.log_batch.extend(batch)
                        break
                except Exception as batch_error:
                    log_error(f"处理日志批次时出错: {str(batch_error)}")
                    # 将失败的批次放回队列末尾
                    self.log_batch.extend(batch)
                    break
            
            # 只在所有批次都成功时提交
            if total_processed == len(logs_to_process):
                try:
                    conn.commit()
                    log_debug(f"成功提交 {total_processed} 条操作日志")
                except Exception as commit_error:
                    log_error(f"提交事务时出错: {str(commit_error)}")
                    # 尝试回滚并将日志放回批次
                    try:
                        conn.rollback()
                    except Exception as rollback_error:
                        log_error(f"事务回滚失败: {str(rollback_error)}")
                    self.log_batch.extend(logs_to_process)
            else:
                try:
                    conn.rollback()
                    log_debug(f"部分日志提交失败，成功: {total_processed}, 失败: {len(logs_to_process) - total_processed}")
                except Exception as rollback_error:
                    log_error(f"部分成功后的事务回滚失败: {str(rollback_error)}")
                
        except Exception as e:
            log_error(f"提交操作日志时出错: {str(e)}")
            # 将处理的日志放回队列，避免丢失
            self.log_batch.extend(logs_to_process)
            if conn:
                try:
                    conn.rollback()
                except Exception as rollback_error:
                    log_error(f"全局异常处理中的事务回滚失败: {str(rollback_error)}")
        finally:
            # 确保连接被正确关闭
            if conn:
                try:
                    DatabaseUtils.close_connection(conn)
                except Exception as close_error:
                    log_error(f"关闭数据库连接时出错: {str(close_error)}")
            # 确保锁被释放
            try:
                self.processing_lock = False
            except Exception as lock_error:
                # 记录错误但不抛出异常
                log_error(f"释放处理锁时出错: {str(lock_error)}")
    
    def log_login(self, username, success=True, detail=None):
        """记录登录操作"""
        self.log_operation(
            username=username,
            operation_module='登录',
            operation_content='用户登录系统',
            operation_result='成功' if success else '失败',
            detail=detail
        )
    
    def log_logout(self, username, detail=None):
        """记录退出登录操作"""
        self.log_operation(
            username=username,
            operation_module='退出登录',
            operation_content='用户退出系统',
            operation_result='成功',
            detail=detail
        )
    
    def log_password_change(self, username, success=True, detail=None):
        """记录密码修改操作"""
        self.log_operation(
            username=username,
            operation_module='密码修改',
            operation_content='修改用户密码',
            operation_result='成功' if success else '失败',
            detail=detail
        )
    
    def log_contract_operation(self, username, contract_no, operation_type, success=True, detail=None):
        """记录合同操作"""
        self.log_operation(
            username=username,
            operation_module='合同管理',
            operation_content=f'{operation_type}合同 {contract_no}',
            operation_result='成功' if success else '失败',
            detail=detail
        )
    
    def log_rent_record_operation(self, username, contract_no, operation_type, success=True, detail=None):
        """记录租金记录操作"""
        self.log_operation(
            username=username,
            operation_module='租金管理',
            operation_content=f'{operation_type}租金记录 {contract_no}',
            operation_result='成功' if success else '失败',
            detail=detail
        )
    
    def log_system_setting_change(self, username, setting_name, old_value, new_value, success=True):
        """记录系统设置变更"""
        detail = {
            'setting_name': setting_name,
            'old_value': old_value,
            'new_value': new_value
        }
        self.log_operation(
            username=username,
            operation_module='系统设置',
            operation_content=f'修改系统设置 {setting_name}',
            operation_result='成功' if success else '失败',
            detail=detail
        )
    
    def log_note_operation(self, username, note_name, operation_type, success=True, detail=None):
        """记录笔记操作"""
        self.log_operation(
            username=username,
            operation_module='笔记管理',
            operation_content=f'{operation_type}笔记 {note_name}',
            operation_result='成功' if success else '失败',
            detail=detail
        )
    
    def get_operation_logs(self, start_date=None, end_date=None, username=None, 
                          operation_module=None, limit=100, offset=0):
        """
        获取操作日志
        
        Args:
            start_date: 开始日期
            end_date: 结束日期
            username: 用户名
            operation_module: 操作模块
            limit: 返回记录数量限制
            offset: 偏移量
        
        Returns:
            日志记录列表
        """
        conn = None
        try:
            conn = self.get_connection()
            if not conn:
                return []
            
            # 构建查询条件
            conditions = []
            params = []
            
            if start_date:
                conditions.append("log_time >= ?")
                params.append(start_date)
            
            if end_date:
                conditions.append("log_time <= ?")
                params.append(f"{end_date} 23:59:59")
            
            if username:
                conditions.append("username = ?")
                params.append(username)
            
            if operation_module:
                conditions.append("operation_module = ?")
                params.append(operation_module)
            
            # 构建SQL查询
            query = "SELECT * FROM operation_logs"
            if conditions:
                query += " WHERE " + " AND ".join(conditions)
            query += " ORDER BY log_time DESC LIMIT ? OFFSET ?"
            
            params.extend([limit, offset])
            
            # 执行查询
            cursor = DatabaseUtils.execute_query(conn, query, params)
            if cursor:
                # 转换为字典列表
                result = [dict(row) for row in cursor.fetchall()]
                return result
            return []
        except Exception as e:
            log_error(f"获取操作日志失败: {str(e)}")
            return []
        finally:
            if conn:
                DatabaseUtils.close_connection(conn)
    
    def __del__(self):
        """析构函数，确保所有日志都被提交"""
        try:
            self.flush_logs()
        except:
            # 析构函数中出错时不抛出异常
            pass
    
    def update_config(self):
        """更新配置设置"""
        config = get_operation_logging_config()
        self.batch_size = config.get('batch_size', 10)
        self.max_batch_age = config.get('max_batch_age', 60)
        self.async_processing = config.get('async_processing', False)

# 创建全局操作日志记录器实例
operation_logger = OperationLogger()

# 简便的日志记录函数
def record_operation(user_id=None, username=None, operation_module=None, 
                    operation_content=None, operation_result=None, detail=None):
    """记录操作日志（简便函数）"""
    operation_logger.log_operation(
        user_id=user_id,
        username=username,
        operation_module=operation_module,
        operation_content=operation_content,
        operation_result=operation_result,
        detail=detail
    )

def record_login(username, success=True, detail=None):
    """记录登录操作（简便函数）"""
    operation_logger.log_login(username, success=success, detail=detail)

def record_logout(username, detail=None):
    """记录退出登录操作（简便函数）"""
    operation_logger.log_logout(username, detail=detail)

def record_password_change(username, success=True, detail=None):
    """记录密码修改操作（简便函数）"""
    operation_logger.log_password_change(username, success=success, detail=detail)

def record_contract_operation(username, contract_no, operation_type, success=True, detail=None):
    """记录合同操作（简便函数）"""
    operation_logger.log_contract_operation(
        username=username,
        contract_no=contract_no,
        operation_type=operation_type,
        success=success,
        detail=detail
    )

def record_rent_record_operation(username, contract_no, operation_type, success=True, detail=None):
    """记录租金记录操作（简便函数）"""
    operation_logger.log_rent_record_operation(
        username=username,
        contract_no=contract_no,
        operation_type=operation_type,
        success=success,
        detail=detail
    )

def record_system_setting_change(username, setting_name, old_value, new_value, success=True):
    """记录系统设置变更（简便函数）"""
    operation_logger.log_system_setting_change(
        username=username,
        setting_name=setting_name,
        old_value=old_value,
        new_value=new_value,
        success=success
    )

def record_note_operation(username, note_name, operation_type, success=True, detail=None):
    """记录笔记操作（简便函数）"""
    operation_logger.log_note_operation(
        username=username,
        note_name=note_name,
        operation_type=operation_type,
        success=success,
        detail=detail
    )

def get_operation_logs(start_date=None, end_date=None, username=None, 
                      operation_module=None, limit=100, offset=0):
    """获取操作日志（简便函数）"""
    return operation_logger.get_operation_logs(
        start_date=start_date,
        end_date=end_date,
        username=username,
        operation_module=operation_module,
        limit=limit,
        offset=offset
    )

def record_security_event(username, event_type, success=True, detail=None):
    """记录安全事件（简便函数）"""
    operation_logger.log_operation(
        username=username,
        operation_module='安全事件',
        operation_content=event_type,
        operation_result='成功' if success else '失败',
        detail=detail
    )